﻿#include "Drawer.h"

GaussianBlurKernel Drawer::createGaussianBlurKernel(float blur_sigma, GLuint shader_program, size_t frame_width, size_t frame_height) {
    GaussianBlurKernel kernel;
    kernel.frameWidth = frame_width;
    kernel.frameHeight = frame_height;
    kernel.shaderProgram = shader_program;

    // 计算高斯核
    float sigma = blur_sigma;
    int radius = static_cast<int>(std::ceil(2.0f * sigma));
    kernel.kernelSize = 2 * radius + 1;
    std::vector<float> weights(kernel.kernelSize);

    float sum = 0.0f;
    kernel.radius = radius;

    for (int i = -radius; i <= radius; ++i) {
        float x = i;
        weights[i + radius] = exp(-x * x / (2 * sigma * sigma));
        sum += weights[i + radius];
    }

    // 归一化
    for (int i = 0; i < kernel.kernelSize; ++i) {
        weights[i] /= sum;
    }
    kernel.weights = std::move(weights);

    // 创建水平模糊FBO和纹理
    glGenFramebuffers(1, &kernel.horizontalFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, kernel.horizontalFBO);

    glGenTextures(1, &kernel.horizontalTexture);
    glBindTexture(GL_TEXTURE_2D, kernel.horizontalTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frame_width, frame_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, kernel.horizontalTexture, 0);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        perror("FBO不完整。\n");
        exit(-1);
    }

    // 获取Uniform位置
    kernel.uWeights = glGetUniformLocation(shader_program, "weights");
    kernel.uDirection = glGetUniformLocation(shader_program, "direction");
    kernel.uTextureSize = glGetUniformLocation(shader_program, "textureSize");

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    float vertices[] = {
        // 位置          // 纹理坐标
        -1.0f,  1.0f,   0.0f, 1.0f, // 左上
        -1.0f, -1.0f,   0.0f, 0.0f, // 左下
         1.0f,  1.0f,   1.0f, 1.0f, // 右上
         1.0f, -1.0f,   1.0f, 0.0f  // 右下
    };

    GLuint vao, vbo;
    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &vbo);

    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 位置属性
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // 纹理坐标属性
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
    glEnableVertexAttribArray(1);

    glBindVertexArray(0);

    kernel.quadVAO = vao;

    return kernel;
}

void Drawer::applyGaussianBlur(GaussianBlurKernel& kernel, GLuint fbo, GLuint rbo, GLuint texture) {
    GLint prevFBO;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFBO);
    GLint prevViewport[4];
    glGetIntegerv(GL_VIEWPORT, prevViewport);

    // ========== 水平模糊阶段 ==========
    glBindFramebuffer(GL_FRAMEBUFFER, kernel.horizontalFBO);
    glViewport(0, 0, kernel.frameWidth, kernel.frameHeight);

    glUseProgram(kernel.shaderProgram);
    glUniform1i(kernel.uDirection, 0);
    glUniform2f(kernel.uTextureSize, kernel.frameWidth, kernel.frameHeight);
    glUniform1fv(kernel.uWeights, kernel.kernelSize, kernel.weights.data());
    glUniform1i(glGetUniformLocation(kernel.shaderProgram, "radius"), kernel.radius);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);

    glBindVertexArray(kernel.quadVAO);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glBindVertexArray(0);

    // ========== 垂直模糊阶段 ==========
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glViewport(0, 0, kernel.frameWidth, kernel.frameHeight);

    // 关键修复：重新绑定程序并设置所有Uniform
    glUseProgram(kernel.shaderProgram); // 必须重新绑定
    glUniform1i(kernel.uDirection, 1);
    glUniform2f(kernel.uTextureSize, kernel.frameWidth, kernel.frameHeight); // 必须重新设置
    glUniform1i(glGetUniformLocation(kernel.shaderProgram, "radius"), kernel.radius); // 必须重新设置

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, kernel.horizontalTexture);

    glBindVertexArray(kernel.quadVAO);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glBindVertexArray(0);

    // 恢复状态
    glBindFramebuffer(GL_FRAMEBUFFER, prevFBO);
    glViewport(prevViewport[0], prevViewport[1], prevViewport[2], prevViewport[3]);
}